package service

import (
	"admin-api/app/dao"
	"admin-api/app/models/entity"
	"admin-api/app/models/request"
	"admin-api/app/models/response"
	"admin-api/app/models/vo"
	"admin-api/core"
	"admin-api/utils"
	"bytes"
	"fmt"
	"gitee.com/molonglove/goboot/gorm"
	"github.com/xuri/excelize/v2"
	"time"
)

var Role = new(RoleService)

type RoleService struct{}

// Page 分页查询
func (r *RoleService) Page(param *request.RolePageRequest) (*response.PageData, *response.BusinessError) {
	var (
		list  []response.RolePageResponse
		total int64
		err   error
	)
	if err = core.DB.Namespace("role").
		DQuery("selectRolePage", param).
		DOffset(param.Page, param.Size).
		TPage(&list, &total).
		Error; err != nil {
		core.Log.Error("查询角色数据失败:%s", err.Error())
		return nil, response.CustomBusinessError(response.Failed, "获取角色数据失败")
	}
	for _, item := range list {
		item.IsSuper = item.RoleId == vo.SUPER_ROLE_ID
	}
	return &response.PageData{
		Total: total,
		Page:  param.Page,
		Size:  param.Size,
		Data:  list,
	}, nil
}

// RoleAll 获取所有角色
func (r *RoleService) RoleAll() (list []response.RoleKeyValueResponse, customErr *response.BusinessError) {
	if err := core.DB.Builder().
		Select(
			gorm.Field("role_id"),
			gorm.Field("role_name"),
		).
		From("sys_role").
		Where(gorm.Eq("del_flag", 1)).
		QExecute(&list).
		Error; err != nil {
		core.Log.Error("获取角色信息失败:%s", err.Error())
		customErr = response.CustomBusinessError(response.Failed, "获取角色数据失败")
	}
	return
}

// Create 角色创建
func (r *RoleService) Create(param *request.RoleCreateRequest) *response.BusinessError {
	var (
		err   error
		count int64
		role  entity.Role
		maps  []*entity.RoleMenu
		now   time.Time
	)
	// 判断是否存在相同的角色名称或者权限字符
	if err = core.DB.Builder().
		Select(gorm.Field("count(1)")).
		From("sys_role").
		Where(
			gorm.Eq("del_flag", 1),
			gorm.Or(
				gorm.Eq("role_name", param.RoleName),
				gorm.Eq("role_key", param.RoleKey),
			),
		).
		QExecute(&count).
		Error; err != nil {
		core.Log.Error("获取角色信息失败:%s", err.Error())
		return response.CustomBusinessError(response.Failed, "获取角色信息失败")
	}
	if count != 0 {
		core.Log.Error("存在相同的角色名称或者权限字符")
		return response.CustomBusinessError(response.Failed, "存在相同的角色名称或者权限字符")
	}
	if err = core.DB.Transaction(func(tx *gorm.DB) error {
		now = time.Now()
		// 创建角色
		role = entity.Role{
			RoleName:   param.RoleName,
			RoleKey:    param.RoleKey,
			RoleSort:   param.RoleSort,
			Status:     param.Status,
			Remark:     param.Remark,
			DelFlag:    1,
			CreateBy:   param.UserName,
			CreateTime: &now,
		}
		if err = dao.Role.Create(tx, &role); err != nil {
			core.Log.Error("创建角色[%s]失败：%s", param.RoleName, err.Error())
			return err
		}
		// 创建角色菜单映射关系
		if len(param.MenuIds) > 0 {
			for _, id := range param.MenuIds {
				maps = append(maps, &entity.RoleMenu{RoleId: role.RoleId, MenuId: id})
			}
			if err = dao.Role.RoleMenuMapping(tx, maps); err != nil {
				core.Log.Error("创建角色[%s]映射关系失败：%s", param.RoleName, err.Error())
				return err
			}
		}
		return nil
	}); err != nil {
		return response.CustomBusinessError(response.Failed, "创建角色失败")
	}
	core.Log.Info("创建角色[%d:%s]成功", role.RoleId, param.RoleName)
	return nil
}

func (r *RoleService) Update(param *request.RoleUpdateRequest) *response.BusinessError {
	var (
		err       error
		maps      []*entity.RoleMenu
		now       time.Time
		old       entity.Role
		customErr *response.BusinessError
		contrast  = func(old *entity.Role, param *request.RoleUpdateRequest) (bErr *response.BusinessError) {
			var (
				count int64
				err   error
			)
			if old.RoleName != param.RoleName {
				// 判断新的角色名称是否存在相同的角色信息
				if err = core.DB.Builder().
					Select(gorm.Count("1")).
					From("sys_role").
					Where(
						gorm.Eq("del_flag", 1),
						gorm.Eq("role_name", param.RoleName),
						gorm.Nq("role_id", old.RoleId),
					).
					QExecute(&count).
					Error; err != nil {
					core.Log.Error("获取角色信息失败:%s", err.Error())
					return response.CustomBusinessError(response.Failed, "获取角色信息失败["+err.Error()+"]")
				}
				if count != 0 {
					return response.CustomBusinessError(response.Failed, "存在相同的角色名称["+param.RoleName+"]")
				}
				old.RoleName = param.RoleName
			}
			if old.RoleKey != param.RoleKey {
				if err = core.DB.Builder().
					Select(gorm.Count("1")).
					From("sys_role").
					Where(
						gorm.Eq("del_flag", 1),
						gorm.Eq("role_key", param.RoleKey),
						gorm.Nq("role_id", old.RoleId),
					).
					QExecute(&count).
					Error; err != nil {
					core.Log.Error("获取角色信息失败:%s", err.Error())
					return response.CustomBusinessError(response.Failed, "获取角色信息失败["+err.Error()+"]")
				}
				if count != 0 {
					return response.CustomBusinessError(response.Failed, "存在相同的权限字符["+param.RoleKey+"]")
				}
				old.RoleKey = param.RoleKey
			}
			old.Status = param.Status
			old.RoleSort = param.RoleSort
			old.Remark = param.Remark
			return nil
		} // 对比是否需要更新数据
	)
	// 获取修改数据
	if old, err = dao.Role.GetRoleById(param.RoleId); err != nil {
		core.Log.Error("当前角色[%d]不存在", param.RoleId)
		return response.CustomBusinessError(response.Failed, "当前角色不存在")
	}
	// 判断是否需要修改数据
	if customErr = contrast(&old, param); customErr != nil {
		core.Log.Error("修改角色失败: %s", customErr.Error())
		return customErr
	}
	// 判断是否需要更新角色和菜单的授权信息
	if len(param.MenuIds) > 0 {
		for _, id := range param.MenuIds {
			maps = append(maps, &entity.RoleMenu{RoleId: old.RoleId, MenuId: id})
		}
	}
	// 执行更新
	if err = core.DB.Transaction(func(tx *gorm.DB) (err error) {
		now = time.Now()
		old.UpdateBy = param.UserName
		old.UpdateTime = &now
		if err = tx.Save(&old).Error; err != nil {
			core.Log.Error("更新角色数据失败:%s", err.Error())
			return
		}
		// 判断是否需要更新映射关系
		if len(maps) > 0 {
			if err = tx.Where("role_id = ?", old.RoleId).Delete(&entity.RoleMenu{}).Error; err != nil {
				core.Log.Error("删除角色菜单旧的映射数据失败:%s", err.Error())
				return
			}
			if err = dao.Role.RoleMenuMapping(tx, maps); err != nil {
				core.Log.Error("创建角色[%s]映射关系失败：%s", param.RoleName, err.Error())
				return
			}
		}
		return
	}); err != nil {
		core.Log.Error("更新角色失败:%s", err.Error())
		return response.CustomBusinessError(response.Failed, "更新角色失败")
	}
	return nil
}

// Info 获取角色详情
func (r *RoleService) Info(roleId int64) (*response.RoleInfoResponse, *response.BusinessError) {
	var (
		role   entity.Role
		result response.RoleInfoResponse
		err    error
	)
	if role, err = dao.Role.GetRoleById(roleId); err != nil {
		return nil, response.CustomBusinessError(response.Failed, "当前角色不存在")
	}
	_ = utils.StructCopy(role, &result)
	// 获取角色分配的菜单数据
	if err = core.DB.Builder().
		Select(gorm.Field("menu_id")).
		From("sys_role_menu").
		Where(gorm.Eq("role_id", roleId)).
		QExecute(&result.MenuIds).
		Error; err != nil {
		core.Log.Error("获取角色和菜单的关联数据失败：%s", err.Error())
	}
	return &result, nil
}

// Delete 角色删除（支持批量）
func (r *RoleService) Delete(param *request.RoleDeleteRequest) *response.BusinessError {
	if err := core.DB.Transaction(func(tx *gorm.DB) (err error) {
		if err = tx.Builder().
			Update().
			Table("sys_role").
			Set(
				gorm.SetField("update_by", param.UserName),
				gorm.SetField("update_time", time.Now()),
				gorm.SetField("del_flag", 0),
			).
			Where(gorm.In("role_id", param.Ids)).
			UExecute().
			Error; err != nil {
			core.Log.Error("删除角色失败：%s", err.Error())
			return err
		}
		if err := tx.Builder().
			Delete().
			From("sys_role_menu").
			Where(gorm.In("role_id", param.Ids)).
			DExecute().
			Error; err != nil {
			core.Log.Error("删除角色关联菜单数据失败：%s", err.Error())
			return err
		}
		return
	}); err != nil {
		return response.CustomBusinessError(response.Failed, "删除角色失败")
	}
	return nil
}

// ChangeStatus 角色状态修改
func (r *RoleService) ChangeStatus(param *request.RoleStatusRequest) *response.BusinessError {
	if err := core.DB.Builder().
		Update().
		Table("sys_role").
		Set(
			gorm.SetField("update_by", param.UserName),
			gorm.SetField("update_time", time.Now()),
			gorm.SetField("status", param.Status),
		).
		Where(gorm.Eq("role_id", param.RoleId)).
		UExecute().
		Error; err != nil {
		core.Log.Error("修改角色状态失败：%s", err.Error())
		return response.CustomBusinessError(response.Failed, "修改角色状态失败")
	}
	return nil
}

func (r *RoleService) DataExport(ids []int64) (file *excelize.File, customErr *response.BusinessError) {
	var (
		sheetStr  string = "角色数据"
		condition *gorm.DB
		sheet     int
		list      []entity.Role
		err       error
	)
	// 创建一个新的Excel文件
	file = excelize.NewFile()
	// 创建一个新的工作表
	if sheet, err = file.NewSheet("角色数据"); err != nil {
		core.Log.Error("导出角色数据失败：%s", err.Error())
		return nil, response.CustomBusinessError(response.Failed, "导出角色数据失败")
	}
	// 设置表头
	_ = file.SetCellValue(sheetStr, "A1", "角色名称")
	_ = file.SetCellValue(sheetStr, "B1", "权限字符")
	_ = file.SetCellValue(sheetStr, "C1", "显示顺序")
	_ = file.SetCellValue(sheetStr, "D1", "角色状态")
	_ = file.SetCellValue(sheetStr, "E1", "创建用户")
	_ = file.SetCellValue(sheetStr, "F1", "备注")
	// 写数据
	condition = core.DB.Where("del_flag = 1 and role_id in ?", ids)
	if list, err = dao.Role.List(condition); err != nil {
		core.Log.Error("读取角色数据失败：%s", err.Error())
		return nil, response.CustomBusinessError(response.Failed, "获取角色数据失败")
	}
	for i, role := range list {
		_ = file.SetCellValue(sheetStr, fmt.Sprintf("A%d", i+2), role.RoleName)
		_ = file.SetCellValue(sheetStr, fmt.Sprintf("B%d", i+2), role.RoleKey)
		_ = file.SetCellValue(sheetStr, fmt.Sprintf("C%d", i+2), role.RoleSort)
		_ = file.SetCellValue(sheetStr, fmt.Sprintf("D%d", i+2), role.Status)
		_ = file.SetCellValue(sheetStr, fmt.Sprintf("E%d", i+2), role.CreateBy)
		_ = file.SetCellValue(sheetStr, fmt.Sprintf("F%d", i+2), role.Remark)
	}
	file.SetActiveSheet(sheet)
	return file, nil
}

func (p *RoleService) DataExport1(ids []int64, sheetName string) (*bytes.Reader, *response.BusinessError) {
	var (
		content   *bytes.Reader
		condition *gorm.DB
		err       error
		list      []entity.Role
	)
	factory := utils.NewFactory[response.RoleExportResponse, entity.Role](sheetName, response.RoleExportResponse{})
	if err = factory.Header(); err != nil {
		core.Log.Error("创建Excel操作句柄失败：%s", err.Error())
		return nil, response.CustomBusinessError(response.Failed, "写入Excel文件失败")
	}
	// 写数据
	condition = core.DB.Where("del_flag = 1 and role_id in ?", ids)
	if list, err = dao.Role.List(condition); err != nil {
		core.Log.Error("读取角色数据失败：%s", err.Error())
		return nil, response.CustomBusinessError(response.Failed, "获取角色数据失败")
	}
	if err = factory.Content(list); err != nil {
		core.Log.Error("写入Excel数据失败：%s", err.Error())
		return nil, response.CustomBusinessError(response.Failed, "写入Excel文件失败")
	}
	if content, err = factory.Build(); err != nil {
		core.Log.Error("写入Excel数据失败：%s", err.Error())
		return nil, response.CustomBusinessError(response.Failed, "写入Excel文件失败")
	}
	return content, nil
}

// UserRole 获取用户拥有的角色
func (r *RoleService) UserRole(userId int64) ([]int64, *response.BusinessError) {
	var (
		ids []int64
		err error
	)
	if err = core.DB.Builder().
		Select(gorm.Field("role_id")).
		From("sys_user_role").
		Where(gorm.Eq("user_id", userId)).
		QExecute(&ids).
		Error; err != nil {
		return nil, response.CustomBusinessError(response.Failed, "获取用户角色数据失败")
	}
	return ids, nil
}

// RoleUser 获取角色拥有的用户信息
func (r *RoleService) RoleUser(roleId int64) ([]int64, *response.BusinessError) {
	var (
		ids []int64
		err error
	)
	if err = core.DB.Builder().
		Select(gorm.Field("user_id")).
		From("sys_user_role").
		Where(gorm.Eq("role_id", roleId)).
		QExecute(&ids).
		Error; err != nil {
		return nil, response.CustomBusinessError(response.Failed, "获取角色用户数据失败")
	}
	return ids, nil
}

// RoleAllocateUser 角色分配用户
func (r *RoleService) RoleAllocateUser(param *request.RoleUserRequest) *response.BusinessError {
	if err := core.DB.Transaction(func(tx *gorm.DB) error {
		if err := tx.Builder().
			Delete().
			From("sys_user_role").
			Where(gorm.Eq("role_id", param.RoleId)).
			DExecute().
			Error; err != nil {
			core.Log.Error("删除角色已有用户映射关系失败:%s", err.Error())
			return err
		}
		//if err := dao.UserRole.DeleteByRoleId(tx, param.RoleId); err != nil {
		//	core.Log.Error("删除角色已有用户映射关系失败:%s", err.Error())
		//	return err
		//}
		list := make([]*entity.UserRole, 0)
		for _, userId := range param.UserIds {
			list = append(list, &entity.UserRole{
				UserId: userId,
				RoleId: param.RoleId,
			})
		}
		if err := dao.UserRole.InsertBatch(tx, list); err != nil {
			core.Log.Error("保存角色已有用户映射关系失败:%s", err.Error())
			return err
		}
		return nil
	}); err != nil {
		return response.CustomBusinessError(response.Failed, "给角色分配用户失败")
	}
	return nil
}

// RoleDataAuth 角色的数据
func (r *RoleService) RoleDataAuth(param *request.RoleDataAuthRequest) *response.BusinessError {
	var (
		updateTime time.Time
		role       entity.Role
		roleDepts  []entity.RoleDept
		err        error
	)
	// 获取角色信息
	if role, err = dao.Role.GetRoleById(param.RoleId); err != nil {
		core.Log.Error("获取角色[%d]失败 => %s", param.RoleId, err.Error())
		return response.CustomBusinessError(response.Failed, "获取角色用户数据失败")
	}
	// 判断数据范围是否为5（自定义部门信息）
	if param.DataType == 2 {
		if len(param.DataValue) <= 0 {
			core.Log.Error("设置数据权限是自定义部门，但是部门信息为空")
			return response.CustomBusinessError(response.Failed, "部门信息不能为空")
		}
		roleDepts = make([]entity.RoleDept, 0)
		for _, deptId := range param.DataValue {
			roleDepts = append(roleDepts, entity.RoleDept{
				RoleId: param.RoleId,
				DeptId: deptId,
			})
		}
	}
	// 更新角色数据
	updateTime = time.Now()
	role.DataScope = param.DataType
	role.UpdateTime = &updateTime
	role.UpdateBy = param.UserName
	if err = core.DB.Transaction(func(tx *gorm.DB) error {
		// 更新角色信息
		if err = tx.Save(&role).Error; err != nil {
			core.Log.Error("更新角色[%d:%s]的数据范围失败:%s", role.RoleId, role.RoleName, err.Error())
			return err
		}
		// 保存角色和部门映射信息
		if len(roleDepts) > 0 {
			if err = tx.Builder().Delete().From("sys_role_dept").Where(gorm.Eq("role_id", param.RoleId)).DExecute().Error; err != nil {
				core.Log.Error("删除角色[%d:%s]旧的数据范围失败:%s", role.RoleId, role.RoleName, err.Error())
				return err
			}
			//if err = tx.Delete(&entity.RoleDept{}, map[string]any{"role_id": param.RoleId}).Error; err != nil {
			//	core.Log.Error("删除角色[%d:%s]旧的数据范围失败:%s", role.RoleId, role.RoleName, err.Error())
			//	return err
			//}
			if err = tx.Create(&roleDepts).Error; err != nil {
				core.Log.Error("保存角色[%d:%s]数据范围失败:%s", role.RoleId, role.RoleName, err.Error())
			}
		}
		return nil
	}); err != nil {
		return response.CustomBusinessError(response.Failed, "设置角色的数据权限失败")
	}
	return nil
}
